﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Resources;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
using RA2VXLEncryption.Forms;

namespace RA2VXLEncryption
{
    public partial class MainForm : Form
    {
        #region 变量
        private readonly ResourceManager rm;
        #endregion

        public MainForm()
        {
            this.InitializeComponent();
            this.rm = new ResourceManager(typeof(RA2VXLEncryptionResource));
        }

        #region 函数
        /// <summary>
        /// 加密后文件的文件名
        /// </summary>
        /// <param name="fileName">含后缀的源文件名或路径</param>
        /// <returns></returns>
        public string EncryptFileName(string fileName)
        {
            string realName = Path.GetFileNameWithoutExtension(fileName);
            realName = Regex.Replace(realName, "_dec$", "") + "_enc";
            return realName + Path.GetExtension(fileName);
        }

        /// <summary>
        /// 解密后文件的文件名
        /// </summary>
        /// <param name="fileName">含后缀的源文件名或路径</param>
        /// <returns></returns>
        public string DecryptFileName(string fileName)
        {
            string realName = Path.GetFileNameWithoutExtension(fileName);
            realName = Regex.Replace(realName, "_enc$", "") + "_dec";
            return realName + Path.GetExtension(fileName);
        }

        /// <summary>
        /// 二进制密钥转为十六进制报文
        /// </summary>
        /// <param name="datas">二进制密钥</param>
        /// <returns></returns>
        public string BinArrayToHexString(byte[] datas)
        {
            StringBuilder builder = new StringBuilder(datas.Length * 2);
            foreach (byte data in datas)
            {
                builder.Append(data.ToString("x2"));
            }
            return builder.ToString();
        }

        /// <summary>
        /// 十六进制报文转为二进制密钥
        /// </summary>
        /// <param name="str">十六进制报文</param>
        /// <returns></returns>
        public byte[] HexStringToBinArray(string str)
        {
            if (str.Length % 2 != 0)
            {
                throw new ArgumentException("字符串长度必须为偶数");
            }
            else
            {
                byte[] datas = new byte[str.Length / 2];
                for (int i = 0; i < str.Length; i += 2)
                {
                    string data = str.Substring(i, 2);
                    datas[i / 2] = Convert.ToByte(data, 16);
                }
                return datas;
            }
        }
        #endregion

        #region 事件
        private void MainForm_Load(object sender, EventArgs e)
        {
            // 启动时检查vpl.dll是否存在
            if (!File.Exists("./DLL/x64/vpl.dll") ||
                !File.Exists("./DLL/x86/vpl.dll"))
            {
                MessageBox.Show(
                    this,
                    "缺失核心文件\"vpl.dll\"",
                    "异常",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
                this.Close();
            }
            // 各种对话框配置
            //this.openFileDialog.Multiselect = true;
            //this.folderBrowserDialog.Description = "";
            // 进度条配置
            this.progressBar.Maximum = 100;
            this.progressBar.Minimum = 0;
        }

        private void buttonAbout_Click(object sender, EventArgs e)
        {
            AboutForm aboutForm = new AboutForm();
            aboutForm.ShowDialog();
        }

        private void buttonCopy_Click(object sender, EventArgs e)
        {
            if (this.textBoxKey.Text.Length == 512)
            {
                // 密钥复制到剪贴板
                Clipboard.SetText(this.textBoxKey.Text);
                this.toolStripStatusLabel.Text = "密钥已复制到剪贴板！";
            }
        }

        private void buttonPaste_Click(object sender, EventArgs e)
        {
            this.textBoxKey.Text = Clipboard.GetText();
            if (this.textBoxKey.Text.Length != 512)
            {
                this.textBoxKey.Text = "";
                MessageBox.Show(
                    this,
                    "输入密钥长度不正确，请检查！",
                    "错误",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
        }

        private async void buttonEncryptVPL_Click(object sender, EventArgs e)
        {
            // 配置文件读取对话框
            this.openFileDialog.Title = this.rm.GetString("VPL_TITLE");
            this.openFileDialog.Filter = this.rm.GetString("VPL_FILE");
            this.openFileDialog.Multiselect = false;
            this.progressBar.Maximum = 100;
            this.progressBar.Value = 0;
            if (this.openFileDialog.ShowDialog() == DialogResult.OK)
            {
                string vplPath = this.openFileDialog.FileName;
                string vplDir = Path.GetDirectoryName(vplPath);
                string vplEncPath = Path.Combine(vplDir, this.EncryptFileName(vplPath));
                if (File.Exists(vplEncPath))
                {
                    File.Delete(vplEncPath);
                }
                File.Create(vplEncPath).Close();
                string key = "";
                this.toolStripStatusLabel.Text = "正在处理……";
                bool result = false;
                await Task.Run(() =>
                {
                    byte[] keyData = new byte[256];
                    // 各种指针初始化
                    IntPtr vplPathPtr = Marshal.StringToHGlobalAnsi(vplPath);
                    IntPtr vplEncPathPtr = Marshal.StringToHGlobalAnsi(vplEncPath);
                    IntPtr keyBuffer = Marshal.AllocHGlobal(256);
                    try
                    {
                        result = VPL.EncryptVPL(vplPathPtr, vplEncPathPtr, keyBuffer, IntPtr.Zero);
                        Marshal.Copy(keyBuffer, keyData, 0, 256);
                        if (result)
                        {
                            // 二进制密钥转为十六进制报文
                            key = this.BinArrayToHexString(keyData);
                        }
                        //Log4NetHelper.Info(this, "VPL加密成功");
                    }
                    catch (Exception ex)
                    {
                        Log4NetHelper.Error(this, "VPL加密失败", ex);
                    }
                    finally
                    {
                        // 内存释放
                        Marshal.FreeHGlobal(vplPathPtr);
                        Marshal.FreeHGlobal(vplEncPathPtr);
                        Marshal.FreeHGlobal(keyBuffer);
                    }
                });
                if (result)
                {
                    this.progressBar.Value = 100;
                }
                this.textBoxKey.Text = key;
                // 密钥复制到剪贴板
                if (key.Length == 512)
                {
                    Clipboard.SetText(key);
                }
                if (result)
                {
                    this.toolStripStatusLabel.Text = "加密VPL处理完毕，密钥已复制到剪贴板，请务必记住密钥！";
                }
                else
                {
                    this.toolStripStatusLabel.Text = "加密VPL失败，文件：" + vplPath;
                    File.Delete(vplEncPath);
                }
            }
        }

        private async void buttonDecryptVPL_Click(object sender, EventArgs e)
        {
            if (this.textBoxKey.Text.Length != 512)
            {
                MessageBox.Show(
                    this,
                    "输入密钥长度不正确，请检查！",
                    "错误",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
            else
            {
                // 配置文件读取对话框
                this.openFileDialog.Title = this.rm.GetString("VPL_TITLE");
                this.openFileDialog.Filter = this.rm.GetString("VPL_FILE");
                this.openFileDialog.Multiselect = false;
                this.progressBar.Maximum = 100;
                if (this.openFileDialog.ShowDialog() == DialogResult.OK)
                {
                    string vplPath = this.openFileDialog.FileName;
                    string vplDir = Path.GetDirectoryName(vplPath);
                    string vplDecPath = Path.Combine(vplDir, this.DecryptFileName(vplPath));
                    if (File.Exists(vplDecPath))
                    {
                        File.Delete(vplDecPath);
                    }
                    File.Create(vplDecPath).Close();
                    this.toolStripStatusLabel.Text = "正在处理……";
                    bool result = false;
                    await Task.Run(() =>
                    {
                        byte[] keyData = HexStringToBinArray(this.textBoxKey.Text);
                        // 各种指针初始化
                        IntPtr vplPathPtr = Marshal.StringToHGlobalAnsi(vplPath);
                        IntPtr vplDecPathPtr = Marshal.StringToHGlobalAnsi(vplDecPath);
                        IntPtr keyBuffer = Marshal.AllocHGlobal(256);
                        Marshal.Copy(keyData, 0, keyBuffer, 256);
                        try
                        {
                            result = VPL.DecryptVPL(vplPathPtr, vplDecPathPtr, keyBuffer);
                            //Log4NetHelper.Info(this, "VPL解密成功");
                        }
                        catch (Exception ex)
                        {
                            Log4NetHelper.Error(this, "VPL解密失败", ex);
                        }
                        finally
                        {
                            // 内存释放
                            Marshal.FreeHGlobal(vplPathPtr);
                            Marshal.FreeHGlobal(vplDecPathPtr);
                            Marshal.FreeHGlobal(keyBuffer);
                        }
                    });
                    if (result)
                    {
                        this.progressBar.Value = 100;
                        this.toolStripStatusLabel.Text = "解密VPL处理完毕！";
                    }
                    else
                    {
                        this.toolStripStatusLabel.Text = "解密VPL失败，文件：" + vplPath;
                        File.Delete(vplDecPath);
                    }
                }
            }
        }

        private async void buttonEncryptVXL_Click(object sender, EventArgs e)
        {
            if (this.textBoxKey.Text.Length != 512)
            {
                MessageBox.Show(
                    this,
                    "输入密钥长度不正确，请检查！",
                    "错误",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
            else
            {
                List<string> vxlPaths = new List<string>();
                // 直接获得该文件夹所有VXL文件
                if (this.checkBoxSelectAll.Checked)
                {
                    folderBrowserDialog.Description = this.rm.GetString("VXL_DIR");
                    if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                    {
                        DirectoryInfo directoryInfo = new DirectoryInfo(folderBrowserDialog.SelectedPath);
                        foreach (FileInfo fi in directoryInfo.GetFiles("*.vxl"))
                        {
                            vxlPaths.Add(fi.FullName);
                        }
                    }
                }
                // 用文件打开对话框多选VXL文件
                else
                {
                    this.openFileDialog.Title = this.rm.GetString("VXL_TITLE");
                    this.openFileDialog.Filter = this.rm.GetString("VXL_FILE");
                    this.openFileDialog.Multiselect = true;
                    if (openFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        vxlPaths.AddRange(openFileDialog.FileNames);
                    }
                }
                if (vxlPaths.Count > 0)
                {
                    this.progressBar.Maximum = vxlPaths.Count;
                    this.progressBar.Value = 0;
                    int successCount = 0;
                    await Task.Run(() =>
                    {
                        string vxlEncDir = Path.Combine(Path.GetDirectoryName(vxlPaths[0]), "Encrypt");
                        if (!Directory.Exists(vxlEncDir))
                        {
                            Directory.CreateDirectory(vxlEncDir);
                        }
                        else
                        {
                            foreach (string file in Directory.GetFiles(vxlEncDir))
                            {
                                File.Delete(file);
                            }
                        }
                        foreach (string path in vxlPaths)
                        {
                            bool result = false;
                            string vxlEncPath = Path.Combine(vxlEncDir, Path.GetFileName(path));
                            byte[] keyData = HexStringToBinArray(this.textBoxKey.Text);
                            // 各种指针初始化
                            IntPtr vxlPathPtr = Marshal.StringToHGlobalAnsi(path);
                            IntPtr vxlEncPathPtr = Marshal.StringToHGlobalAnsi(vxlEncPath);
                            IntPtr keyBuffer = Marshal.AllocHGlobal(256);
                            Marshal.Copy(keyData, 0, keyBuffer, 256);
                            try
                            {
                                result = VPL.EncryptVXL(keyBuffer, vxlPathPtr, vxlEncPathPtr);
                                if (result)
                                {
                                    successCount++;
                                }
                            }
                            catch (Exception ex)
                            {
                                Log4NetHelper.Error(this, "VXL加密失败", ex);
                            }
                            finally
                            {
                                // 内存释放
                                Marshal.FreeHGlobal(vxlPathPtr);
                                Marshal.FreeHGlobal(vxlEncPathPtr);
                                Marshal.FreeHGlobal(keyBuffer);
                                Action action = () => progressBar.Increment(1);
                                progressBar.Invoke(action);
                                Thread.Sleep(500);
                            }
                        }
                        this.toolStripStatusLabel.Text = $"VXL加密处理完毕，成功{successCount}个，共计{vxlPaths.Count}个"; ;
                    });
                }
            }
        }

        private async void buttonDecryptVXL_Click(object sender, EventArgs e)
        {
            if (this.textBoxKey.Text.Length != 512)
            {
                MessageBox.Show(
                    this,
                    "输入密钥长度不正确，请检查！",
                    "错误",
                    MessageBoxButtons.OK,
                    MessageBoxIcon.Error);
            }
            else
            {
                List<string> vxlPaths = new List<string>();
                // 直接获得该文件夹所有VXL文件
                if (this.checkBoxSelectAll.Checked)
                {
                    folderBrowserDialog.Description = this.rm.GetString("VXL_DIR");
                    if (folderBrowserDialog.ShowDialog() == DialogResult.OK)
                    {
                        DirectoryInfo directoryInfo = new DirectoryInfo(folderBrowserDialog.SelectedPath);
                        foreach (FileInfo fi in directoryInfo.GetFiles("*.vxl"))
                        {
                            vxlPaths.Add(fi.FullName);
                        }
                    }
                }
                // 用文件打开对话框多选VXL文件
                else
                {
                    this.openFileDialog.Title = this.rm.GetString("VXL_TITLE");
                    this.openFileDialog.Filter = this.rm.GetString("VXL_FILE");
                    this.openFileDialog.Multiselect = true;
                    if (openFileDialog.ShowDialog() == DialogResult.OK)
                    {
                        vxlPaths.AddRange(openFileDialog.FileNames);
                    }
                }
                if (vxlPaths.Count > 0)
                {
                    this.progressBar.Maximum = vxlPaths.Count;
                    this.progressBar.Value = 0;
                    int successCount = 0;
                    await Task.Run(() =>
                    {
                        string vxlDecDir = Path.Combine(Path.GetDirectoryName(vxlPaths[0]), "Decrypt");
                        if (!Directory.Exists(vxlDecDir))
                        {
                            Directory.CreateDirectory(vxlDecDir);
                        }
                        else
                        {
                            foreach (string file in Directory.GetFiles(vxlDecDir))
                            {
                                File.Delete(file);
                            }
                        }
                        foreach (string path in vxlPaths)
                        {
                            bool result = false;
                            string vxlDecPath = Path.Combine(vxlDecDir, Path.GetFileName(path));
                            byte[] keyData = HexStringToBinArray(this.textBoxKey.Text);
                            // 各种指针初始化
                            IntPtr vxlPathPtr = Marshal.StringToHGlobalAnsi(path);
                            IntPtr vxlDecPathPtr = Marshal.StringToHGlobalAnsi(vxlDecPath);
                            IntPtr keyBuffer = Marshal.AllocHGlobal(256);
                            Marshal.Copy(keyData, 0, keyBuffer, 256);
                            try
                            {
                                result = VPL.DecryptVXL(keyBuffer, vxlPathPtr, vxlDecPathPtr);
                                if (result)
                                {
                                    successCount++;
                                }
                            }
                            catch (Exception ex)
                            {
                                Log4NetHelper.Error(this, "VXL解密失败", ex);
                            }
                            finally
                            {
                                // 内存释放
                                Marshal.FreeHGlobal(vxlPathPtr);
                                Marshal.FreeHGlobal(vxlDecPathPtr);
                                Marshal.FreeHGlobal(keyBuffer);
                                Action action = () => progressBar.Increment(1);
                                progressBar.Invoke(action);
                                Thread.Sleep(500);
                            }
                        }
                        this.toolStripStatusLabel.Text = $"VXL解密处理完毕，成功{successCount}个，共计{vxlPaths.Count}个"; ;
                    });
                }
            }
        }
        #endregion
    }
}
